feat(python-codegen): @column field naming, server-default exprs, --entities allowlist#79
Merged
Merged
Conversation
…ntities allowlist Three consumer-facing gaps surfaced by generating Python record models from the SAME entity metadata that drives the TypeScript Drizzle layer: 1. @column-aware Pydantic field naming. The entity/value generator emitted `field.name` verbatim, so a model authored camelCase for the TS port (`callPurpose` + `@column: call_purpose`) produced camelCase Python fields that don't match the DB columns. The Pydantic field name is now `@column` when present, else `field.name` — one entity feeds both languages idiomatically (camelCase TS property, snake_case Python field = the physical column). Backward-compatible: no @column emits identically. 2. Server-side default EXPRESSIONS are no longer rendered as Python literal defaults. A string @default matching the SQL-expression patterns (now, now(), current_timestamp/date/time, anything ending in `()` such as gen_random_uuid()) is DB-filled, so emitting `id: uuid.UUID = "gen_random_uuid()"` was wrong. Such a field now carries no Python default (keeps its required/optional shape); literal defaults (bool/int/str/enum) are unchanged. Mirrors the TS column-mapper's SQL_EXPR_PATTERNS so both ports agree on what counts as an expression. 3. `metaobjects gen --entities <names>` allowlist. The whole model is still loaded (so `extends` bases and @objectref VOs resolve), but only the named entities are emitted — generate a subset of a shared model without splitting the metadata. Wired through `gen` and `verify --codegen` (run_gen already supported entity_filter). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Minor bump for the backward-compatible codegen features in the previous commit (@column field naming, server-default expressions, --entities allowlist) and to align the Python port with the 0.12.x line. pyproject + uv.lock self-version only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Surfaced by generating Python record models from the same entity metadata that drives the TypeScript Drizzle layer (one cross-language source of truth). Three consumer-facing gaps blocked that, all in the Python port's
entity_modelgenerator + CLI — no metamodel/registry change, so no cross-port conformance reconciliation is needed.Changes
1.
@column-aware Pydantic field naming. The generator emittedfield.nameverbatim, so an entity authored camelCase for the TS port (callPurpose+@column: call_purpose) produced camelCase Python fields that don't match the DB columns. The Pydantic field name is nowfield.column ?? field.name— one entity feeds both languages idiomatically (camelCase TS property, snake_case Python field = the physical column). Backward-compatible: a model with no@columnemits byte-identically.2. Server-side default expressions are no longer rendered as Python literal defaults. A string
@defaultmatching the SQL-expression patterns (now,now(),current_timestamp/date/time, anything ending in()such asgen_random_uuid()) is DB-filled — soid: uuid.UUID = "gen_random_uuid()"was invalid. Such a field now carries no Python default (keeps its required/optional shape). Literal defaults (bool/int/str/enum) are unchanged. Mirrors the TScolumn-mapper.tsSQL_EXPR_PATTERNSso both ports agree on what counts as an expression.3.
metaobjects gen --entities <names>allowlist. The whole model is still loaded (soextendsbases and@objectRefVOs resolve), but only the named entities are emitted — generate a subset of a shared model without splitting the metadata. Wired throughgenandverify --codegen;run_genalready supportedentity_filter.Tests
New regression tests in
test_entity_model.py(column override, fallback, server-default-expr vs literal) andtest_cli.py(entities allowlist emit + verify in sync). Fulltests/codegensuite green except two pre-existingtest_cli_staleness_nudgefailures unrelated to this change (they fail on cleanorigin/maintoo).Also bumps the Python port to
0.12.0(backward-compatible minor; aligns with the 0.12.x line).